package com.leo.foodmaster.admin.system.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.leo.foodmaster.admin.system.dto.PermissionRolesDTO;
import com.leo.foodmaster.admin.system.entity.Meta;
import com.leo.foodmaster.admin.system.entity.Permission;
import com.leo.foodmaster.admin.system.entity.RolePermission;
import com.leo.foodmaster.admin.system.entity.Router;
import com.leo.foodmaster.admin.system.mapper.PermissionMapper;
import com.leo.foodmaster.admin.system.service.IPermissionService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.leo.foodmaster.admin.system.service.IRolePermissionService;
import com.leo.foodmaster.commons.constants.AuthConstants;
import com.leo.foodmaster.commons.entity.Result;
import com.leo.foodmaster.commons.entity.TreeSelect;
import com.leo.foodmaster.commons.util.WebUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 菜单权限表 服务实现类
 * </p>
 *
 * @author Leo
 * @since 2021-06-18
 */
@Service
public class PermissionServiceImpl extends ServiceImpl<PermissionMapper, Permission> implements IPermissionService {
    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    @Resource
    private IRolePermissionService rolePermissionService;
    private static final String ADMIN = "admin";

    /**
     * 刷新权限角色管理到Redis缓存
     */
    @Override
    public void refreshPermissionRolesToCache() {
        // 1、删除Redis中的权限角色关系缓存
        redisTemplate.delete(AuthConstants.PERMISSION_ROLES_KEY);
        // 2、查询权限角色关系
        List<PermissionRolesDTO> permissionRoles = baseMapper.listPermissionRoles();
        Map<String, List<String>> permissionRoleMap = new TreeMap<>();
        Optional.ofNullable(permissionRoles).orElse(new ArrayList<>()).forEach(item -> {
            // 转换 roleId -> ROLE_{roleId}
            List<String> roles = Optional.ofNullable(item.getRoleIds()).orElse(new ArrayList<>()).stream()
                    .map(roleId -> AuthConstants.ROLE + roleId).collect(Collectors.toList());

            if (CollUtil.isNotEmpty(roles)) {
                permissionRoleMap.put(item.getMethod() + "_" + item.getUri(), roles);
            }
            redisTemplate.opsForHash().putAll(AuthConstants.PERMISSION_ROLES_KEY, permissionRoleMap);
        });
    }

    /**
     * 根据登录用户Id查询用户权限
     * @param userId 用户Id
     * @return 用户权限列表
     */
    @Override
    public List<String> getPermissionsByUserId(Long userId) {
        return baseMapper.getPermissionsByUserId(userId);
    }

    /**
     * 根据用户Id查询路由树形列表
     * @param userId 机构用户Id
     * @return  List<RouterDTO>
     */
    @Override
    public List<Router> getRoutersByUserId(Long userId) {
        List<Router> list = baseMapper.getRoutersByUserId(userId, 0L);
        list.forEach(router -> getChildrenList(router, userId));
        return list;
    }

    /**
     * 获取子路由
     * @param router 父路由
     */
    private void getChildrenList(Router router, Long userId) {
        Meta meta = new Meta();
        meta.setTitle(router.getTitle());
        meta.setIcon(router.getIcon());
        meta.setNoCache(router.getNoCache());
        router.setMeta(meta);
        router.setChildren(new ArrayList<>());

        List<Router> routers = baseMapper.getRoutersByUserId(userId, router.getId());
        // 如果该路由有子路由
        if (!routers.isEmpty()) {
            router.setChildren(routers);
            router.setRedirect("noRedirect");
            router.setAlwaysShow(routers.size() > 1);
            routers.forEach(item -> getChildrenList(item, userId));
        }
    }

    /**
     * 查询菜单列表
     * @return List<Permission>
     */
    @Override
    public List<Permission> listPermission(String title, String status) {
        return list(Wrappers.lambdaQuery(Permission.class)
                        .like(StrUtil.isNotBlank(title), Permission::getTitle, title)
                        .eq(StrUtil.isNotBlank(status), Permission::getStatus, status)
                        .orderByAsc(Permission::getOrderNum));
    }

    /**
     * 查询菜单树形列表
     * @param userId 用户Id
     * @return List<TreeSelect>
     */
    @Override
    public List<TreeSelect> treeSelect(Long userId) {
        // 如果登录用户为平台管理员，则拥有所有菜单权限
        String account = WebUtils.getUser().getAccount();
        if (ADMIN.equals(account)) {
            userId = null;
        }

        List<TreeSelect> list = baseMapper.getMenuTreeByUserId(userId, 0L);
        getChildrenTree(list, userId);
        return list;
    }

    /**
     * 查询子树列表
     * @param list 父树列表
     * @param userId 用户Id
     */
    private void getChildrenTree(List<TreeSelect> list, Long userId) {
        if (!list.isEmpty()) {
            list.forEach(item -> {
                List<TreeSelect> children = baseMapper.getMenuTreeByUserId(userId, item.getId());
                if (!children.isEmpty()) {
                    item.setChildren(children);
                    getChildrenTree(children, userId);
                }
            });
        }
    }

    /**
     * 根据角色Id查询菜单树形列表
     * @param id 角色Id
     * @return List<TreeSelect>
     */
    @Override
    public List<Long> permissionIdsByRoleId(Long id) {
        return baseMapper.permissionIdsByRoleId(id);
    }

    /**
     * 删除权限
     * @param id 权限Id
     * @return Result<Object>
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Object> deletePermission(Long id) {
        // 如果该菜单下有子菜单，则该菜单不能被删除
        int count = count(Wrappers.lambdaQuery(Permission.class)
                .eq(Permission::getParentId, id));
        if (count != 0) {
            return Result.fail("该菜单下有子菜单，不能删除！");
        }
        // 如果该权限有角色正在使用，不能删除该权限
        int rolePermissionCount = rolePermissionService.count(Wrappers.lambdaQuery(RolePermission.class)
                .eq(RolePermission::getPermissionId, id));
        if (rolePermissionCount != 0) {
            return Result.fail("有角色正在使用该菜单，不能删除！");
        }
        // 删除角色权限关系表
        rolePermissionService.remove(Wrappers.lambdaUpdate(RolePermission.class)
                .eq(RolePermission::getPermissionId, id));
        // 删除权限表
        boolean remove = removeById(id);
        return Result.success(remove);
    }


}
